/*
 *  Copyright 2015-2016, RenGu Technology (BeiJing) Co., Ltd.
 *  All right reserved.
 *
 *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF RENGU TECHNOLOGY (BeiJing) CO., LTD.
 *
 *  THE CONTENTS OF THIS FILE MAY NOT BE DISCLOSED TO THIR PARTIES,
 *  COPIED OR DUPLICATED IN ANY FORM, IN WHOLE OR IN PART,
 *  WITHOUT THE PRIOR WRITTEN PERMISSION OF RENGU TECHNOLOGY (BeiJing) CO., LTD.
 *
 *  VirtAcctPreAuth
 *
 *  Edit History:
 *      lizhangtao Created on 2020年04月12日
 *
 */
package cc.rengu.igas.acct.core.service.trans;

import cc.rengu.igas.acct.common.dao.AcctDetailMapper;
import cc.rengu.igas.acct.common.dao.MapperCommon;
import cc.rengu.igas.acct.common.dao.impl.AcctDetailMapperImpl;
import cc.rengu.igas.acct.common.entity.AcctDetail;
import cc.rengu.igas.acct.common.enums.AcctRespCodeEnum;
import cc.rengu.igas.acct.common.enums.AcctTransStatusEnum;
import cc.rengu.igas.acct.common.enums.AcctTxnNumEnum;
import cc.rengu.igas.acct.common.util.CheckCutDayUtil;
import cc.rengu.igas.acct.core.service.realize.AcctOpt;
import cc.rengu.igas.acct.facade.bean.MultiMchntPreAuthDetail;
import cc.rengu.igas.acct.facade.request.VirtAcctMultiMchntPreAuthCancelRequest;
import cc.rengu.igas.acct.facade.response.VirtAcctMultiMchntPreAuthCancelResponse;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.utility.util.BeanUtil;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.DbsUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.base.StringUtil;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**
 * 预授权撤销
 * 原有冻结的金额转到可用余额，整体账户余额不变
 *
 * @author lizhangtao
 * @version 1.0
 * @date 2020/5/8
 */
public class VirtAcctMultiMchntPreAuthCancelService extends RadpService {

    @Override
    protected int bizInit(String s) {
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            VirtAcctMultiMchntPreAuthCancelRequest virtAcctMultiMchntPreAuthCancelRequest = new VirtAcctMultiMchntPreAuthCancelRequest();
            ConvertUtil.convertOutput(virtAcctMultiMchntPreAuthCancelRequest);
            rglog.info("virtAcctMultiMchntPreAuthCancelRequest = <{}>", JSONObject.toJSONString(virtAcctMultiMchntPreAuthCancelRequest));
            VirtAcctMultiMchntPreAuthCancelResponse virtAcctMultiMchntPreAuthCancelResponse = new VirtAcctMultiMchntPreAuthCancelResponse();
            virtAcctMultiMchntPreAuthCancelResponse.setHeader(virtAcctMultiMchntPreAuthCancelRequest.getHeader());
            BizResponse<VirtAcctMultiMchntPreAuthCancelResponse> bizResponse = new BizResponse<>();
            List<MultiMchntPreAuthDetail> mchtPreAuthDetailList = new ArrayList<MultiMchntPreAuthDetail>();
            virtAcctMultiMchntPreAuthCancelResponse.setMchtPreAuthDetailList(mchtPreAuthDetailList);
            bizResponse.setResult(virtAcctMultiMchntPreAuthCancelResponse);
            String frontSeqNum = virtAcctMultiMchntPreAuthCancelRequest.getTransSeqNum();
            String transDate = virtAcctMultiMchntPreAuthCancelRequest.getHeader().getTransDate();
            String transTime = virtAcctMultiMchntPreAuthCancelRequest.getHeader().getTransTime();
            String txnNum = virtAcctMultiMchntPreAuthCancelRequest.getHeader().getTxnNum();
            String srcSysId = virtAcctMultiMchntPreAuthCancelRequest.getHeader().getSrcSysId();
            String instId = virtAcctMultiMchntPreAuthCancelRequest.getHeader().getInstId();
            String traceNo = virtAcctMultiMchntPreAuthCancelRequest.getHeader().getTraceNo();
            //使用前端流水号获取登记的多商户明细
            AcctDetailMapper acctDetailMapper = new AcctDetailMapperImpl();
            List<AcctDetail> acctDetailList = acctDetailMapper.fetchListByFrontSeqNum(instId, frontSeqNum);
            if (null == acctDetailList || 0 == acctDetailList.size()) {
                throw new BizException(AcctRespCodeEnum.NO_TRANS_RECORD.getRespCode(), AcctRespCodeEnum.NO_TRANS_RECORD.getRespDesc());
            }
            String txnNumOrig = acctDetailList.get(0).getTxnNum();
            //只支持多商户交易的查询 单笔记账、预授权、预授权撤销、预授权完成
            if (AcctTxnNumEnum.isSingle(txnNumOrig)) {
                rglog.error("只支持单笔交易的查询 单笔记账、预授权、预授权撤销、预授权完成;而被查询的交易为<{}><{}>",
                        txnNum, AcctTxnNumEnum.getInstance(txnNumOrig).getDesc());
                throw new BizException(AcctRespCodeEnum.ILLEGAL_OPR_ERROR.getRespCode(),
                        AcctRespCodeEnum.ILLEGAL_OPR_ERROR.getRespDesc());
            }
            if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getTxnNum().equals(txnNumOrig))) {
                rglog.error("不都是同一个交易，原记账有问题");
                throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(),
                        AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
            }
            String acctStatusOrig = acctDetailList.get(0).getAcctStatus();
            if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getAcctStatus().equals(acctStatusOrig))) {
                rglog.error("不都是同一个状态，原记账有问题");
                throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(),
                        AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
            }
            String debitCreditFlagOrig = acctDetailList.get(0).getDebitCreditFlag();
            if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getDebitCreditFlag().equals(debitCreditFlagOrig))) {
                rglog.error("不都是同一个记账类型，原记账有问题");
                throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(),
                        AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
            }
            String acctDateOrig = acctDetailList.get(0).getAcctDate();
            if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getAcctDate().equals(acctDateOrig))) {
                rglog.error("不都是同一个记账日期，原记账有问题");
                throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(),
                        AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
            }
            String remark2Orig = acctDetailList.get(0).getRemark2();
            if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getRemark2().equals(remark2Orig))) {
                rglog.error("不都是同一个remark2（记录交易明细总数），原记账有问题");
                throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(),
                        AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
            }
            //多商户原交易查询，对比成功的交易笔数，针对预授权若已经被撤销或者完成返回该交易已经被撤销或者完成
            int totalRecords = Integer.parseInt(remark2Orig);
            if (totalRecords != acctDetailList.size()) {
                rglog.error("交易笔数对不上，原记账有问题");
                throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(),
                        AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
            }
            //2. 开启事物
            String dbPoolName = MapperCommon.getDbPoolName();
            DbsUtil dbsUtil = new DbsUtil(dbPoolName);
            dbsUtil.dbsBeginTransaction();
            try {
                //检查记账日期
                String acctDate = CheckCutDayUtil.check(instId, dbsUtil);
                for (AcctDetail acctDetailTmp : acctDetailList) {
                    //冻结撤销操作
                    AcctDetail acctDetail = new AcctOpt().freezeCancel(transDate, transTime, txnNum, srcSysId, instId, traceNo,
                            acctDetailTmp.getAcctSeqNum(), acctDetailTmp.getTransAmt(), acctDetailTmp.getAcctNo(),
                            acctDetailTmp.getCustomerId(), acctDetailTmp.getUserType(), acctDetailTmp.getUserId(),
                            acctDetailTmp.getSummary(), rglog, acctDate, dbsUtil, totalRecords);
                    if (null == acctDetail) {
                        //一般不出现该情况，出现该情况为系统异常
                        throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
                    }
                    MultiMchntPreAuthDetail multiMchntPreAuthDetail = new MultiMchntPreAuthDetail();
                    BeanUtil.beanCopy(acctDetail, multiMchntPreAuthDetail);
                    mchtPreAuthDetailList.add(multiMchntPreAuthDetail);
                }
                //再次检查记账日期
                new AcctOpt().acctDateConfirm(instId, acctDate, dbsUtil, rglog);
            } catch (Exception e) {
                dbsUtil.dbsEndTransaction(false);
                throw e;
            }
            dbsUtil.dbsEndTransaction(true);

            virtAcctMultiMchntPreAuthCancelResponse.setRespCode(OltpRpcdEnum.TRANS_SUCCESS.getRespCode());
            virtAcctMultiMchntPreAuthCancelResponse.setRespDesc(OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
            virtAcctMultiMchntPreAuthCancelResponse.setTransStatus(AcctTransStatusEnum.SUCC.getStatus());
            bizResponse.setRspSysId(ChannelEnum.ACCT.getChannelType());
            bizResponse.setTransStatus(TransStatusEnum.TRANS_SUCC);
            bizResponse.setRespCode(OltpRpcdEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
            ConvertUtil.convertInput(bizResponse.getResult());
        } catch (BizException e) {
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, e.getCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, e.getMessage());
            } catch (Exception e1) {
                rglog.error(StringUtil.ExceptionToString(e1));
            }
        } catch (Exception e) {
            rglog.error(StringUtil.ExceptionToString(e));
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE,
                        OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC,
                        OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespDesc());
            } catch (Exception e1) {
                rglog.error(StringUtil.ExceptionToString(e));
            }
        }
        return 0;
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }
}
